/* 
 * Copyright (c) 2018, S.F. Express Inc. All rights reserved.
 */
package com.sf.trtms.trade.personal.utils;

import java.io.IOException;
import java.security.NoSuchAlgorithmException;

import javax.annotation.PostConstruct;
import javax.net.ssl.SSLContext;

import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;

/**
 * 描述：in.close();作用就是将用完的连接释放，下次请求可以复用，这里特别注意的是，如果不使用in.close();而仅仅使用response.close();结果就是连接会被关闭，并且不能被复用，这样就失去了采用连接池的意义。
    连接池释放连接的时候，并不会直接对TCP连接的状态有任何改变，只是维护了两个Set，leased和avaliabled，leased代表被占用的连接集合，avaliabled代表可用的连接的集合，释放连接的时候仅仅是将连接从leased中remove掉了，并把连接放到avaliabled集合中
 
 经测试 response.close() 没什么影响？
 * 
 * <pre>HISTORY
 * ****************************************************************************
 *  ID   DATE           PERSON          REASON
 *  1    2018年10月12日      01380297         Create
 * ****************************************************************************
 * </pre>
 * @author 01380297
 * @since 1.0
 */
@Component
public class HttpConnectionManager {

	private static final Logger logger = LoggerFactory.getLogger(HttpConnectionManager.class);
	private static final String UTF8 = "UTF-8";
	
	private PoolingHttpClientConnectionManager cm = null;
    
	/** 连接池总连接数，当路由总数大于此值，则会变成普通http请求，连接会继续涨 */
	@Value("${ground.personal.trade.http.pool.maxTotal:50000}")
    private int maxTotal = 50000;
    
	/** 每个ip:port的最大连接数 */
	@Value("${ground.personal.trade.http.pool.defaultMaxPerRoute:2000}")
    private int defaultMaxPerRoute = 2000;

    @PostConstruct
    public void init() throws NoSuchAlgorithmException {
        LayeredConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(SSLContext.getDefault());
        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
                .register("https", sslsf)
                .register("http", new PlainConnectionSocketFactory())
                .build();
        cm =new PoolingHttpClientConnectionManager(socketFactoryRegistry);
        cm.setMaxTotal(maxTotal);//整个连接池的最大连接数
        cm.setDefaultMaxPerRoute(defaultMaxPerRoute);// //是路由的默认最大连接（该值默认为2），限制数量实际使用DefaultMaxPerRoute并非MaxTotal。如果为1 则等于
    }

    public CloseableHttpClient getHttpClient() {
    	return HttpClients.custom()
                .setConnectionManager(cm)
                .build();          
        /** CloseableHttpClient httpClient = HttpClients.createDefault();//如果不采用连接池就是这种方式获取连接*/
    }
    
    /**
     * get 请求返回序列化为java类
     * @param path
     */
    public String get(String path){
        CloseableHttpClient httpClient = this.getHttpClient();
        HttpGet httpget = new HttpGet(path);
        String json = null;        
        CloseableHttpResponse response=null;
        try {
            response = httpClient.execute(httpget);
            if (response != null && response.getEntity() != null) {
            	json = EntityUtils.toString(response.getEntity(), UTF8); 
            }
            logger.debug("get {} response {}", path, json);
        } catch (Exception e) {
        	logger.error("", e);
        } finally {    
        	try {
        		if (response != null)
        			EntityUtils.consume(response.getEntity()); //会自动释放连接
	            if (response != null) {
	                response.close();
	            }   
	        } catch (IOException e) {
	        	logger.error("", e);
	        }
        }                
        return json;
    }
 
    /**
     * post 请求
     * @param path
     * @param jsonParams
     * @return
     * T
     */
    public String post(String path, String jsonParams){
        CloseableHttpClient httpClient = this.getHttpClient();
        HttpPost httpPost = new HttpPost(path);
        httpPost.addHeader(HTTP.CONTENT_TYPE, "application/json");

        String responseJson = null;        
        CloseableHttpResponse response=null;
        try {
        	if (jsonParams != null && !jsonParams.trim().equals(""))
        		httpPost.setEntity(new StringEntity(jsonParams, UTF8));
            response = httpClient.execute(httpPost);
            if (response != null && response.getEntity() != null) {
            	responseJson = EntityUtils.toString(response.getEntity(), UTF8); 
            }
            logger.debug("post {} jsonParams {} response {}", path, jsonParams, responseJson);
        } catch (Exception e) {
        	logger.error("", e);
        } finally {    
        	try {
        		if (response != null)
        			EntityUtils.consume(response.getEntity()); //会自动释放连接
	            if (response != null) {
	                response.close();
	            }   
	        } catch (IOException e) {
	        	logger.error("", e);
	        }
        }                
        return responseJson;
    }
    
    /**
     * post 请求
     * @param path
     * @param jsonParams
     * @param clazz
     * @return
     * T
     */
    public <T> T post(String path, String jsonParams, Class<T> clazz){
        CloseableHttpClient httpClient = this.getHttpClient();
        HttpPost httpPost = new HttpPost(path);
        httpPost.addHeader(HTTP.CONTENT_TYPE, "application/json");

        String responseJson = null;        
        CloseableHttpResponse response=null;
        try {
        	if (jsonParams != null && !jsonParams.trim().equals(""))
        		httpPost.setEntity(new StringEntity(jsonParams, UTF8));
            response = httpClient.execute(httpPost);
            if (response != null && response.getEntity() != null) {
            	responseJson = EntityUtils.toString(response.getEntity(), UTF8); 
            }
            logger.debug("post {}jsonParams {} response {}", path, jsonParams, responseJson);
        } catch (Exception e) {
        	logger.error("", e);
        } finally {
        	try {
        		if (response != null)
        			EntityUtils.consume(response.getEntity()); //会自动释放连接
	            if (response != null) {
	                response.close();
	            }   
	        } catch (IOException e) {
	        	logger.error("", e);
	        }
        }
        return JSON.parseObject(responseJson, clazz);
    }
/**    
    public static void main(String[] args) {
    	HttpConnectionManager httpConnectionManager = new HttpConnectionManager();
    	httpConnectionManager.init();
    	String string = httpConnectionManager.get("https://www.baidu.com");
    	System.err.println(string);
	}
    
    public static void main1(String[] args) {
    	HttpConnectionManager httpConnectionManager = new HttpConnectionManager();
    	httpConnectionManager.init();
    	String string = httpConnectionManager.post("http://localhost:8080/post2?data=测试打他", null);
    	System.err.println(string);
	}
    
    public static void main2(String[] args) {
    	Object parseObject = JSON.parseObject(null, Object.class);
    	parseObject = JSON.parseObject("", Object.class);
    	System.err.println(parseObject);
	}*/
}
